﻿#include "cuda_runtime.h"
#include "device_launch_parameters.h"


#include <string> 
#include <cufft.h> 
#include <cuda.h> 
#include <iostream> 
#include <opencv2/opencv.hpp>
#include "dft.hpp"
#include "dwt.hpp"
#include "utility.hpp"
using namespace std;
using namespace cv;

typedef float2 complex;



int main(void)
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Load image data to array data</summary>
	/// <remarks>	Quan, 6/18/2012. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	const char* filename = "Lenna_gray_512.jpg";
	const int nRows = 512;
	const int nCols = 512;
	Mat img;
// 	float2* data;
// 	data = (float2*)malloc(nRows*nCols*sizeof(float2));
// 	
// 	img = imread(filename, IMREAD_GRAYSCALE);
// 	for(int i=0; i<nRows; i++)
// 	{
// 		for(int j=0; j<nCols; j++)
// 		{
// 			data[i*nCols + j].x = (float)img.at<uchar>(i, j);
// 			data[i*nCols + j].y = 0;
// 		}
// 	}
	float2* data;
	data = (float2*)malloc(nRows*nCols*sizeof(float2));

	img = imread(filename, IMREAD_GRAYSCALE);
	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			data[i*nCols + j].x = (float)img.at<uchar>(i, j);
			data[i*nCols + j].y = 0;
		}
	}
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Load mask data </summary>

	////////////////////////////////////////////////////////////////////////////////////////////////////
	FileStorage fs;

	Mat mask_vardens;
	fs = FileStorage("mask_vardens.xml", FileStorage::READ);
	fs["mask_vardens"] >> mask_vardens;
	fs.release();

	Mat pdf_vardens;
	fs = FileStorage("pdf_vardens.xml", FileStorage::READ);
	fs["pdf_vardens"] >> pdf_vardens;
	fs.release();

	float2* mask;
	mask = (float2*)malloc(nRows*nCols*sizeof(float2));
	float2* pdf;
	pdf  = (float2*)malloc(nRows*nCols*sizeof(float2));

	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			mask[i*nCols + j].x = (float)mask_vardens.at<double>(i, j);
			mask[i*nCols + j].y = (float)mask_vardens.at<double>(i, j);

			pdf [i*nCols + j].x = (float)pdf_vardens.at<double>(i, j);
			pdf [i*nCols + j].y = (float)pdf_vardens.at<double>(i, j);
		}
	}
	/// <summary>	Copy data from CPU to GPU </summary>
	float2 *d_mask;
	float2 *d_pdf;

	cudaMalloc((void**)&d_mask, sizeof(float2)*nRows*nCols);
	cudaMemcpy(d_mask,    mask, sizeof(float2)*nRows*nCols, cudaMemcpyHostToDevice);
	cudaMalloc((void**)&d_pdf,  sizeof(float2)*nRows*nCols);
	cudaMemcpy(d_pdf,     pdf,  sizeof(float2)*nRows*nCols, cudaMemcpyHostToDevice);


// 	float2 *d_data;
// 	cudaMalloc((void**)&d_data, sizeof(float2)*nRows*nCols);
// 	cudaMemcpy(d_data,    data, sizeof(float2)*nRows*nCols, cudaMemcpyHostToDevice);

	float2 *d_data;
	cudaMalloc((void**)&d_data, sizeof(float2)*nRows*nCols);
	cudaMemcpy(d_data,    data, sizeof(float2)*nRows*nCols, cudaMemcpyHostToDevice);

	/// <summary>	Perform Forward Fourier Transform </summary>
	//cuda::dft(d_data, d_data, nRows, nCols, cuda::DFT_FORWARD);

	/// <summary>	Multiply with Mask </summary>
	//cuda::multiply(d_data, d_mask, d_data, nRows, nCols);
	/// <summary>	Divide by Point Distribution Function </summary>
	//cuda::divide(d_data, d_pdf, d_data, nRows, nCols);

	/// <summary>	Perform Forward Wavelet Transform </summary>
	//cuda::dwt(data, data, nRows, nCols, 8, cuda::DWT_FORWARD);
	//cuda::dwt(data, data, nRows, nCols, 8, cuda::DWT_INVERSE);

	cuda::dwt(d_data, d_data, nRows, nCols, 8, cuda::DWT_FORWARD);
	//cuda::dwt(d_data, d_data, nRows, nCols, 8, cuda::DWT_INVERSE);
	/// <summary>	Perform Inverse Fourier Transform </summary>
	//cuda::dft(d_data, d_data, nRows, nCols, cuda::DFT_INVERSE|DFT_SCALE);

	/// <summary>	Copy data from GPU to CPU </summary>
	cudaMemcpy(data, d_data, sizeof(float2)*nRows*nCols, cudaMemcpyDeviceToHost);
	//cudaMemcpy(data, d_data, sizeof(float2)*nRows*nCols, cudaMemcpyDeviceToHost);
// 	for(int i=0; i<500; i++)
// 	{
// 		cout << data[i].x <<"\t" << data[i].y << "\t";	
// 	}

	img.convertTo(img, CV_32FC1);
	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			img.at<float>(i, j) = data[i*nCols + j].x;
			//img.at<uchar>(i, j) = (uchar)data[i*nCols + j].x;
			//data[i*nCols + j].y = 0;
			//cout << *(data + (i*nCols+j)) << endl;
		}
	}

	fs = FileStorage("data.xml", FileStorage::WRITE);
	fs << "data"  << img;
	fs.release();

	img.convertTo(img, CV_8UC1);
	cv::imshow("Image", img);
	//cv::imwrite("Blend.jpg", img);
	cv::waitKey();
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>	Forward Fourier Transform </summary>
	/// <remarks>	Quan, 6/18/2012. </remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////

	free(data);
}